package com.njupt.simulation.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 复数类，用于存储和操作复数
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Complex {
    private double real; // 实部
    private double imag; // 虚部

    /**
     * 常见的复数常量
     */
    public static final Complex ZERO = new Complex(0.0, 0.0);
    public static final Complex ONE  = new Complex(1.0, 0.0);
    public static final Complex I    = new Complex(0.0, 1.0);

    /**
     * 计算复数的模长 |z|
     *
     * @return 模长
     */
    public double magnitude() {
        return Math.sqrt(real * real + imag * imag);
    }

    /**
     * 计算复数的相位 arg(z)，范围 (-π, π]
     *
     * @return 相位（弧度）
     */
    public double argument() {
        return Math.atan2(imag, real);
    }

    /**
     * 复数相加
     * @param other 另一个复数
     * @return 相加后的新复数
     */
    public Complex add(Complex other) {
        return new Complex(this.real + other.real, this.imag + other.imag);
    }

    /**
     * 复数相减
     * @param other 另一个复数
     * @return 相减后的新复数
     */
    public Complex subtract(Complex other) {
        return new Complex(this.real - other.real, this.imag - other.imag);
    }

    /**
     * 复数相乘 (a + bi)*(c + di) = (ac - bd) + (ad + bc)i
     * @param other 另一个复数
     * @return 相乘后的新复数
     */
    public Complex multiply(Complex other) {
        double newReal = this.real * other.real - this.imag * other.imag;
        double newImag = this.real * other.imag + this.imag * other.real;
        return new Complex(newReal, newImag);
    }

    /**
     * 复数相除 (a + bi)/(c + di) = [(ac + bd) + (bc - ad)i] / (c^2 + d^2)
     * @param other 另一个复数
     * @return 相除后的新复数
     */
    public Complex divide(Complex other) {
        double denominator = other.real * other.real + other.imag * other.imag;
        if (denominator == 0.0) {
            throw new ArithmeticException("Divide by zero in complex division");
        }
        double newReal = (this.real * other.real + this.imag * other.imag) / denominator;
        double newImag = (this.imag * other.real - this.real * other.imag) / denominator;
        return new Complex(newReal, newImag);
    }

    /**
     * 取共轭 (a + bi) => (a - bi)
     * @return 复数的共轭
     */
    public Complex conjugate() {
        return new Complex(this.real, -this.imag);
    }

    /**
     * 按标量进行倍乘 k*(a + bi) = (k*a) + (k*b)i
     * @param k 标量
     * @return 倍乘后的新复数
     */
    public Complex scale(double k) {
        return new Complex(this.real * k, this.imag * k);
    }

    /**
     * 通过极坐标 (r, theta) 构造复数
     * @param r     模长
     * @param theta 相位（弧度）
     * @return 复数
     */
    public static Complex fromPolar(double r, double theta) {
        double real = r * Math.cos(theta);
        double imag = r * Math.sin(theta);
        return new Complex(real, imag);
    }

    /**
     * 重写 equals()，当实部和虚部都"足够接近"时，认为两者相等
     * 也可使用严格判断 real == other.real && imag == other.imag
     * 这里用误差判断避免浮点数陷阱
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Complex)) return false;
        Complex other = (Complex) o;
        double epsilon = 1e-12; // 允许的浮点比较误差
        return (Math.abs(this.real - other.real) < epsilon) &&
                (Math.abs(this.imag - other.imag) < epsilon);
    }

    /**
     * 重写 hashCode() 保证和 equals() 兼容
     */
    @Override
    public int hashCode() {
        // 可以将实部和虚部的 double 位解析为 long 再做哈希，也可以做简单组合
        long bitsReal = Double.doubleToLongBits(real);
        long bitsImag = Double.doubleToLongBits(imag);
        return (int) (bitsReal ^ (bitsReal >>> 32) ^
                bitsImag ^ (bitsImag >>> 32));
    }

    /**
     * 返回复数的字符串表示
     */
    @Override
    public String toString() {
        return String.format("%.4f %s %.4fj",
                real,
                (imag >= 0) ? "+" : "-",
                Math.abs(imag));
    }
}
